package com.quanxiaoha.xiaohashu.auth.exception;

import com.quanxiaoha.framework.common.exception.BizException;
import com.quanxiaoha.framework.common.response.Response;
import com.quanxiaoha.xiaohashu.auth.enums.ResponseCodeEnum;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.View;

import java.util.Optional;

/**
 * @author: Jovan
 * @date: 2024/11/21
 * @description:
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    private final View error;

    public GlobalExceptionHandler(View error) {
        this.error = error;
    }

    /**
     * 处理业务异常的全局异常处理器
     * 当控制器层或服务层抛出BizException时，此方法将捕获异常并返回统一的响应对象
     *
     * @param request HttpServletRequest对象，用于获取请求信息
     * @param e BizException对象，包含错误代码和错误信息
     * @return Response<Object> 返回包含错误信息的响应对象
     */
    @ExceptionHandler({BizException.class})
    @ResponseBody
    public Response<Object> handleBizException(HttpServletRequest request, BizException e) {
        // 记录业务异常日志，包括请求URI、错误代码和错误信息
        log.warn("{} request fail,errorCode: {},errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getMessage());
        // 返回包含业务异常信息的失败响应
        return Response.fail(e);
    }

    // 处理方法参数校验不通过的异常
    @ExceptionHandler({ MethodArgumentNotValidException.class })
    @ResponseBody
    public Response<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        // 设置错误码
        String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();

        // 获取校验结果
        BindingResult bindingResult = e.getBindingResult();

        StringBuilder sb = new StringBuilder();

        // 获取校验不通过的字段，并组合错误信息，格式为： email 邮箱格式不正确, 当前值: '123124qq.com';
        Optional.ofNullable(bindingResult.getFieldErrors()).ifPresent(errors -> {
            errors.forEach(error ->
                    sb.append(error.getField())
                            .append(" ")
                            .append(error.getDefaultMessage())
                            .append(", 当前值: '")
                            .append(error.getRejectedValue())
                            .append("'; ")

            );
        });

        // 错误信息
        String errorMessage = sb.toString();

        // 记录日志
        log.warn("{} request error,errorCode: {},errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);

        // 返回错误响应
        return Response.fail(errorCode, sb.toString());
    }
    /**
     * 全局异常处理方法
     * 用于处理除已明确处理的异常外的其他所有异常
     *
     * @param request HttpServletRequest对象，包含当前请求的信息
     * @param e Exception对象，表示捕获到的异常
     * @return Response<Object> 返回一个包含错误信息的响应对象
     */
    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Response<Object> handleOtherException(HttpServletRequest request, Exception e) {
        // 记录错误日志，包括请求的URI和异常信息
        log.error("{} request error", request.getRequestURI(),e);
        // 返回系统错误的响应
        return Response.fail(ResponseCodeEnum.SYSTEM_ERROR);
    }

    /**
     * 捕获 guava 参数校验异常
     * @return
     */
    @ExceptionHandler({ IllegalArgumentException.class })
    @ResponseBody
    public Response<Object> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        // 参数错误异常码
        String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();

        // 错误信息
        String errorMessage = e.getMessage();

        log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);

        return Response.fail(errorCode, errorMessage);
    }
}
